//deviceController.js
//获取应用实例

const jm = require("./encAndDes.js");
const app = getApp()
export const defaultKey = 'CA5BD38AE85973FD7759EC02' //默认的密钥
class BleLockHelper {
  constructor() {
    this.data = {
      LS_COMM_SESSION: 0x01, //设置session 0x1
      LS_COMM_TIME: 0x02, //更新时间 2
      LS_COMM_PWD: 0x03, //密码操作 增加 删除 修改 3
      LS_COMM_OPEN: 0x04, //开门 4
      LS_COMM_CHIPKEY: 0x05, //配置密钥 5
      LS_COMM_DEVICE: 0x06, //读取设备信息 6
      LS_COMM_DEVICE_ID: 0x07, //设置设备ID 7
      LS_COMM_OPENLOG: 0x08, //开门记录 8
      LS_COMM_HEARBEAT: 0x09, //心跳 3s  9
      LS_COMM_MSG: 0x0a, //获取MSG a
      LS_COMM_OFFLINE: 0x0b, //设置离线密码编号+开关 b
      LS_COMM_PINCODE: 0x0c, //配对 c
      LS_COMM_BATT_VALUE: 0x0d, //d
      LS_COMM_UPDATE: 0x0e, //升级 e
      LS_COMM_PROJECT: 0x0f, //工程版本 f
      LS_COMM_CLEAR: 0x10, //清空 10
      LS_COMM_PWD_VALID: 0x11, //密码操作 增加 删除 修改--生效有效期 11
      LS_COMM_USER_VALID: 0x12, //密码操作 增加 删除 修改--生效有效期 12
      LS_COMM_OPENLOG_BIGDATA: 0x13, //开门记录 13
      LS_COMM_MAX_GET_MCUID: 0x71, //获设备MCU ID
    }
    this.session = "00000000"
    this.keys = "CA5BD38AE85973FD7759EC0200000000"
    this.serviceId = "0000fff0-0000-1000-8000-00805f9b34fb"
    this.receiveId = "0000fff6-0000-1000-8000-00805f9b34fb"
    this.iosGetMacServiceId = "0000180A-0000-1000-8000-00805F9B34FB"
    this.sendId = "0000fff6-0000-1000-8000-00805f9b34fb"
    this.secretKey = "CA5BD38AE85973FD7759EC02" //设置的chipKey,会更改的哈14e1b600b1fd579f47433b88
    //如果是ios可能这个值还没设置
    this.deviceId = "AB:67:55:44:33:88"
    //这个值应该肯定会有
    this.mac = "AB:67:55:44:33:88"

    this.userCharacteristcID = "0000FFF6-0000-1000-8000-00805F9B34FB"
    this.sendInterval = 0
    //开门记录回调
    this.openLogCallback = null
    //开门回调
    this.openCallback = null
    //设置，增删改回调
    this.setUserCallback = null
    //清空用户或历史记录回调
    this.clearUserCallback = null
    //设置密钥回调
    this.chipCallback = null
    //发送回调
    this.sendCallback = null
    //获取mcuId回调
    this.getMcuCallback = null
    //心跳5秒未收到，回调此 
    this.heartFailCallback = null
    //获取电量
    this.batteryCallback = null
    //获取锁信息
    this.lockInfoCallback = null


    this.initSuccessCallback = null
    this.initFailCallback = null

    this.reconnectCount = 0
    this.lastHeartTime = 0
    this.onBLECharacteristicValueChangeListener = null
  }

  clearAllCallback() {
    //开门记录回调
    this.openLogCallback = null
    //开门回调
    this.openCallback = null
    //设置，增删改回调
    this.setUserCallback = null
    //清空用户或历史记录回调
    this.clearUserCallback = null
    //设置密钥回调
    this.chipCallback = null
    //发送回调
    this.sendCallback = null
    //获取mcuId回调
    this.getMcuCallback = null
    //心跳5秒未收到，回调此 
    this.heartFailCallback = null
    this.batteryCallback = null
    //获取锁信息
    this.lockInfoCallback = null

    this.initSuccessCallback = null
    //关闭蓝牙或心跳超过5秒未收到或连接失败等情况下回调
    this.initFailCallback = null
    this.reconnectCount = 0

    wx.offBLECharacteristicValueChange(this.onBLECharacteristicValueChangeListener)
  }

  /**
   * 停止心跳
   */
  stopHeart() {
    clearInterval(this.sendInterval)
  }

  /**
   * 连接到蓝牙门锁
   */
  connect(deviceId, successCallback, failCallback) {
    var that = this
    this.keys = this.secretKey + this.session
    if (deviceId) {
      this.deviceId = deviceId
    }
    this.initSuccessCallback = successCallback
    this.initFailCallback = failCallback
    console.log("ble 连接", deviceId)
    wx.createBLEConnection({
      deviceId: that.deviceId,
      success: function (res) {
        //配对
        that.getServiceAndCharacteristics(that.deviceId)
      },
      fail: function (res) {
        if (res.errCode === -1) {
          //createBLEConnection:fail:already connect
          successCallback()
          return
        }
        that.reconnectCount++
        if (that.reconnectCount >= 3) {
          that.initFailCallback("连接到蓝牙门锁失败")
        } else {
          console.log("ble", "连接蓝牙失败，重试")
          console.log("ble", res)

          that.connect(that.deviceId, successCallback, failCallback)
        }
      }
    })
  }

  /****
   * 获取发送数据命令 
   * 参数：命令字cmd 内容数组 p 内容长度length 是否加密 isEncryption
   * 返回：内容字符串
   */
  Inferface_GetSendData(cmd, p, length, isEncryption) {
    if (isEncryption) {
      let list = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
      var i;
      var check;
      for (i = 0; i < length; i++) {
        list[i] = p[i];
        check ^= list[i];
      }

      let str = this.byteToString(list);
      if (cmd != this.data.LS_COMM_HEARBEAT) {
        console.log("ble发送加密前data", str)
        console.log("ble发送加密keys", this.keys)

      }

      var data = jm.encryptionData(str, this.keys);
      // console.log("加密", data);
      let buffer = this.StringToByte(data);
      return this.Inferface_GetMakeData(cmd, buffer, 16);
    } else {
      return this.Inferface_GetMakeData(cmd, p, length);
    }
  }

  Inferface_GetMakeData(cmd, p, length) {
    var buf = [];
    var checkSum = 0;
    var i = 0;
    buf[0] = 0x7f;
    buf[1] = length + 2;
    buf[2] = cmd;

    if (length > 0) {
      for (i = 0; i < length; i++) {
        buf[3 + i] = p[i];
      }
    }

    for (i = 0; i < length + 3; i++)
      checkSum ^= buf[i];
    buf[i] = checkSum;

    var result = this.byteToString(buf)
    this.BlueToothCentral_Data_Send_Data(result, cmd);

    if (cmd != this.data.LS_COMM_HEARBEAT) {
      console.log("ble", '发送cmd:' + cmd)
      console.log("ble发送data", result)
    }

    return result;
  }


  /****
   * 解密数据
   * 参数：p 16位数组
   * 返回：解密后数组
   */
  Inferface_GetDecryptData(p) {
    var str = this.byteToString(p);
    var jdata = jm.decryptData(str, this.keys);
    // console.log("解密前", str);
    // console.log("解密结果", jdata);
    return this.StringToByte(jdata);
  }

  /****
   * 发送数据
   * 参数：str 字符串
   * 返回：无
   */
  BlueToothCentral_Data_Send_Data(str, cmd) {
    var that = this
    var deviceId = this.deviceId
    // console.log('发送', device)

    // var tempSendData = this.data.inputData
    var tempSendData = str; //"7f120c8f9240b8c453073b423151a845dc7afbbd";
    var buffer = that.stringToHexBuffer(tempSendData)
    // console.log("send data:", tempSendData);
    // console.log("send data:", buffer);
    // console.log("deviceId:" + deviceId);
    // console.log("serviceId:" + that.getServiceId());
    // console.log("characteristicId:" + that.getSendId());

    wx.writeBLECharacteristicValue({
      deviceId: deviceId,
      serviceId: that.getServiceId(),
      characteristicId: that.getSendId(),
      value: buffer,
      success: function (res) {
        // success
        // console.log('ble 发送成功:', res)
        //that.addData({ dataType: "发送", content: tempSendData })
        that.sendCallback && that.sendCallback({
          success: true,
          cmd: cmd
        })
      },
      fail: function (res) {
        // fail
        console.log('ble 发送失败:', res)
        console.log('ble 发送失败:', "cmd:" + cmd)

        that.sendCallback && that.sendCallback({
          success: false,
          cmd: cmd,
          data: res
        })
      },
      complete: function (res) {
        // complete
        // console.log('write', res)
      }
    })
  }


  /****
   * 获取Session
   * 参数：无
   * 返回：
   */
  blueGetSession = function () {
    var list = [];
    console.log("处理SESSION")
    return this.Inferface_GetSendData(this.data.LS_COMM_SESSION, list, 0, false);
  }

  /****
   * 发送配对
   * 参数：无
   * 返回：
   */
  blueSendPin = function () {
    console.log("发送配对")
    var tempSendData = "7f120c8f9240b8c453073b423151a845dc7afbbd";
    this.BlueToothCentral_Data_Send_Data(tempSendData);
    return tempSendData;
  }

  /****
   * 发送心跳
   * 参数：无
   * 返回：
   */
  blueSendHead = function () {
    // console.log("发送心跳")
    //var tempSendData = "7f020974";
    //that.addData({ dataType: "其他", content: '发送心跳:' + tempSendData })
    //this.BlueToothCentral_Data_Send_Data(tempSendData);
    return this.Inferface_GetSendData(this.data.LS_COMM_HEARBEAT, null, 0, false);
  }
  /****
   * 发送远程开门
   * 参数：
   * 返回：
   */
  blueSendOpen = function () {
    //	明文内容：sessio id，1字节校验和。
    var list = [];
    var i = 0;
    var check = 0;
    console.log("远程开门");
    let buffer = this.StringToByte(this.session);

    for (i = 0; i < 4; i++) {
      list[i] = buffer[i];
      check ^= list[i];
    }
    list[4] = check;
    //console.log("远程开门", array1);
    //console.log("远程开门", list);
    return this.Inferface_GetSendData(this.data.LS_COMM_OPEN, list, 5, true);
  }

  /****
   * 获取电量 
   * 参数：无
   * 返回：
   */
  blueSendBatt = function () {
    console.log("获取电量")
    return this.Inferface_GetSendData(this.data.LS_COMM_BATT_VALUE, null, 0, false);
  }

  /****
   * 读取设备信息
   * 参数：无
   * 返回：
   */
  blueSendDeviceMsg = function () {
    console.log("读取设备信息")
    return this.Inferface_GetSendData(this.data.LS_COMM_DEVICE, null, 0, false);
  }

  /****
   * 读取项目版本信息
   * 参数：无
   * 返回：
   */
  blueSendProjectMsg = function () {
    console.log("读取项目版本信息")
    return this.Inferface_GetSendData(this.data.LS_COMM_PROJECT, null, 0, false);
  }

  /****
   * 读取锁ＭＣＵ　ＩＤ
   * 参数：无
   * 返回：
   */
  blueSendMCUID = function () {
    console.log("读取锁MCU ID")
    return this.Inferface_GetSendData(this.data.LS_COMM_MAX_GET_MCUID, null, 0, false);
  }

  /****
   * 获取开门记录
   * 参数：uId 记录下标   最新一次为1
   * 返回：
   */
  blueSendOpenLog = function (uId) {
    var list = [];
    console.log("获取开门记录")
    console.log("uId:", uId)
    list[0] = uId / 0x100;
    list[1] = uId % 0x100;
    return this.Inferface_GetSendData(this.data.LS_COMM_OPENLOG_BIGDATA, list, 2, false);
  }

  /****
   * 设置离线密码信息值
   * 参数：openFlg 开关标志[0无 1开 2关]   type 类型 密码组编号[0无  1-5范围]
   * 返回：
   */
  blueSendOffLineValue = function (openFlg, type) {
    var list = [];
    console.log("openFlg:", openFlg)
    console.log("type:", type)
    list[0] = openFlg;
    list[1] = type;
    return this.Inferface_GetSendData(this.data.LS_COMM_OFFLINE, list, 2, true);
  }

  /****
   * 清空数据
   * 参数：type 清空类型 1 用户 2开门记录
   * 返回：
   */
  blueSendClearData = function (type) {
    var list = [];
    console.log("清空数据")
    console.log("type:", type)

    var i = 0;
    var check = 0;

    let buffer = this.StringToByte(this.session);

    if (type == 1) {
      list[4] = 0x5E;
    } else if (type == 2) {
      list[4] = 0x6F;
    } else {
      return;
    }

    for (i = 0; i < 4; i++) {
      list[i] = buffer[i];
      check ^= list[i];
    }
    check ^= list[4];
    list[5] = check;
    return this.Inferface_GetSendData(this.data.LS_COMM_CLEAR, list, 6, true);
  }

  /****
   * 设置时间
   * 参数：timeValue var list = [0x20, 0x17, 0x12, 0x23, 0x09, 0x30, 0x06];
   * 返回：
   * var list = [0x20, 0x17, 0x12, 0x23, 0x09, 0x30, 0x06];
   */
  blueSendTime = function (timeValue) {
    // var list = [0x20, 0x17, 0x12, 0x23, 0x09, 0x30, 0x06];
    console.log("设置时间", timeValue)
    //size 数组长度 timebuf 时间数组 (2bytes),月(1byte),日(1byte),时(1byte),分(1byte),星期(1byte)
    return this.Inferface_GetSendData(this.data.LS_COMM_TIME, timeValue, 7, false);
  }

  /****
   * 设置密钥
   * str 12位新的密钥字符串
   * 返回：
   */
  blueSendChipkey = function (str) {
    var list = [];
    console.log("设置密钥")
    console.log("str:", str)
    if (str == this.secretKey) {
      this.chipCallback && this.chipCallback({ success: true })
      return
    }

    var i = 0;
    var check = 0;

    let buffer = this.StringToByte(str);

    for (i = 0; i < 12; i++) {
      list[i] = buffer[i];
      check ^= list[i];
    }
    list[12] = check;
    return this.Inferface_GetSendData(this.data.LS_COMM_CHIPKEY, list, 13, true);
  }



  /****
   * 操作用户 增加删除及修改
   * 参数：操作类型 type,
   * 高4位:0表示添加，1表示删除，2表示修改有效期
   * 低4位:0表示指纹，1代表密码，2代表钥匙，3代表卡,
   * 0xb为密码管理员
   * 
   * 开始时间 startTime,2021年3月20日10时50分(10*5)表示如下
   *     21 * 0x40000 + 3 * 0x4000 + 20 * 0x200 + 10 * 0x10 + 10;;
   *     000，代表永久有效
   * 结束时间 endTime,2021年3月20日10时50分(10*5)表示如下21 * 0x40000 + 3 * 0x4000 + 20 * 0x200 + 10 * 0x10 + 10;;
   *      用户编号 uid,
   *      用户内容数组 data,
   *      内容长度 dataLen,
   *      是否为管理员 isAdmin
   * 返回：
   * data "123456"
   */
  blueSendChangeUser(type, startTime, endTime, uid, data, dataLen) {
    var timeList = [];
    // console.log("操作用户 增加删除及修改")
    // console.log("操作类型", type)
    // console.log("开始时间", startTime)
    // console.log("结束时间", endTime)
    // console.log("用户编号", uid)

    // console.log("用户内容数组", data)
    // console.log("内容长度", dataLen)
    //console.log("是否为管理员", isAdmin)

    // console.log("用户内容数组", data)
    // console.log("内容长度", dataLen)
    //console.log("是否为管理员", isAdmin)
    console.log('ble 用户', 'type:' + type + ',uid:' + uid)

    timeList[0] = type;
    timeList[1] = startTime / 0x10000;
    timeList[2] = startTime / 0x100 % 0x100;
    timeList[3] = startTime % 0x100;
    timeList[4] = endTime / 0x10000;
    timeList[5] = endTime / 0x100 % 0x100;
    timeList[6] = endTime % 0x100;
    timeList[7] = uid / 0x100 % 0x100;
    timeList[8] = uid % 0x100;
    timeList[9] = dataLen % 0x100;
    var i;
    var byteArr = this.StringToByte(data)
    for (i = 0; i < dataLen; i++) {
      timeList[10 + i] = byteArr[i];
    }
    // this.addData({
    //   dataType: "其他",
    //   content: this.byteToString(timeList)
    // })
    return this.Inferface_GetSendData(this.data.LS_COMM_USER_VALID, timeList, dataLen + 10, true);
  }


  /****
   * 操作密码用户 增加删除及修改
   * 参数：新密码 newPwd,
   *      旧密码 oldPwd,
   *      开始时间 startTime,
   *      结束时间 endTime,
   *      用户编号 uid,
   * 返回：
   */
  blueSendOldChangeUser = function (newPwd, oldPwd, startTime, endTime, uid) {
    var timeList = [];
    var i, check;
    console.log("操作密码用户 增加删除及修改")
    console.log("新密码", newPwd)
    console.log("旧密码", oldPwd)
    console.log("开始时间", startTime)
    console.log("结束时间", endTime)
    console.log("用户编号", uid)

    var lp = this.intToByte(newPwd, 3);
    for (i = 0; i < 3; i++) {
      timeList[0 + i] = lp[i];
    }
    var lp2 = this.intToByte(oldPwd, 3);
    // this.memcpy(timeList, lp2, 3,0, 3);
    for (i = 0; i < 3; i++) {
      timeList[3 + i] = lp2[i];
    }
    var lp3 = this.intToByte(startTime, 4);
    // this.memcpy(timeList, lp3, 6,0, 4);
    for (i = 0; i < 4; i++) {
      timeList[6 + i] = lp3[i];
    }
    var lp4 = this.intToByte(endTime, 4);
    //this.memcpy(timeList, lp4, 10,0, 4);
    for (i = 0; i < 4; i++) {
      timeList[10 + i] = lp4[i];
    }
    timeList[14] = uid % 0x100;

    for (i = 0; i < 15; i++) {
      check ^= timeList[i];
    }
    timeList[15] = check;
    console.log("操作密码用户", this.byteToString(timeList))
    // this.addData({ dataType: "其他", content: this.byteToString(timeList) })
    return this.Inferface_GetSendData(this.data.LS_COMM_PWD_VALID, timeList, 16, true);
  }

  /****
   * 定时器发送心跳
   * 参数：无
   * 返回：
   */
  sendHeadCode() {
    var that = this;
    if (this.sendInterval) {
      clearInterval(this.sendInterval)
    }
    this.lastHeartTime = new Date().getTime()
    this.sendInterval = setInterval(function () {
      that.blueSendHead();
      that.checkReceiveHeart()
    }, 3500)
  }

  /**
   * 检查心跳
   */
  checkReceiveHeart() {
    if (new Date().getTime() - this.lastHeartTime > 5000) {
      //心跳超过5秒未收到
      // this.initFailCallback("连接已断开")
      //停止发送心跳包
      this.stopHeart()
      this.heartFailCallback && this.heartFailCallback()
    }
  }

  /****
   * 接收数据处理结果
   * 参数：无
   * 返回：
   */
  blueRecieve = function (bufs) {
    var that = this;
    //var bufs2 = that.arraybuffToHexBuffer(bufs)
    //let buf = Array.prototype.slice.call(new Uint8Array(bufs2));
    var cmd;
    var list1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    let i;
    let cnum;

    let buf = this.StringToByte(bufs);
    cmd = buf[2];
    var headLen = buf[1];

    if (cmd != that.data.LS_COMM_HEARBEAT) {
      console.log('接收数据:' + bufs)
      console.log('接收处理 cmd:' + cmd)
    }

    switch (cmd) {
      case that.data.LS_COMM_OPEN:
        if (buf[3] == 0) {
          console.log("ble", '开门成功')
          that.openCallback({
            success: true,
            data: '开门成功'
          })
        } else {
          console.log("ble", '开门失败')
          that.openCallback({
            success: false,
            data: '开门失败'
          })
        }
        break;
      case that.data.LS_COMM_HEARBEAT:
        //that.addData({ dataType: "其他", content: '心跳成功' })
        // console.log("ble", '心跳成功')
        //心跳时间戳
        that.lastHeartTime = new Date().getTime()
        break;
      case that.data.LS_COMM_SESSION:
        that.memcpy(list1, buf, 3, 16);
        var jdata2 = this.Inferface_GetDecryptData(list1);
        console.log("解密", jdata2);
        cnum = 0;
        for (i = 0; i < 4; i++) {
          cnum ^= jdata2[i];
        }
        //未验证校验码
        // if (jdata2[4] != cnum) {
        //return;
        // }

        let list = [0x0, 0x0, 0x0, 0x0];
        this.memcpy(list, jdata2, 0, 4);

        var str2 = this.byteToString(list);
        let newKey = that.secretKey + str2;
        console.log("session:", str2);
        console.log("new key:", newKey);
        that.session = str2
        that.keys = newKey

        // that.setData({
        //   session: str2,
        //   keys: newKey,
        // });

        console.log("ble", 'session成功')
        //校正时间，始终相信手机时间是正确的
        // [0x20, 0x17, 0x12, 0x23, 0x09, 0x30, 0x06];
        //    20   17年   12月  23 日 9时   30分   6秒
        that.sendHeadCode();
        that.blueSendDate(new Date())
        setTimeout(() => {
          that.blueSendBatt()
        }, 40);
        setTimeout(() => {
          that.initSuccessCallback && that.initSuccessCallback()
        }, 60);
        break;
      case that.data.LS_COMM_PINCODE:
        if (buf[3] == 0) {
          console.log("ble", '配对成功')
          that.blueGetSession();
        } else {
          console.log("ble", '配对失败')
          that.initFailCallback("配对失败")
        }

        break;

      case that.data.LS_COMM_TIME: // 0x02,//更新时间 2
        if (buf[3] == 0) {
          console.log("ble", '更新时间成功')
        } else {
          console.log("ble", '更新时间失败')
        }
        break;

      case that.data.LS_COMM_CHIPKEY: //0x05,//配置密钥 5
        if (buf[3] == 0) {
          console.log("ble", '配置密钥成功')
          that.chipCallback && that.chipCallback({
            success: true
          })
        } else {
          console.log("ble", '配置密钥失败')
          that.chipCallback && that.chipCallback({
            success: false
          })
        }
        break;

      case that.data.LS_COMM_DEVICE: //0x06,//读取设备信息 6
        if (headLen == 18) {
          console.log("ble", '读取设备ID成功')
          var devId = [];
          var HardV = buf[14 + 3];
          var softV = buf[15 + 3];

          this.memcpy(devId, buf, 3, 14);
          var deviceId = that.array2mac(devId)
          console.log("ble 设备IDarray:", devId)
          console.log("ble", '设备ID:' + deviceId)
          console.log("ble", 'HardV' + HardV)
          console.log("ble", 'softV' + softV)
          that.lockInfoCallback && that.lockInfoCallback({ success: true, data: deviceId })
        } else {
          console.log("ble", "读取设备ID失败")
          that.lockInfoCallback && that.lockInfoCallback({ success: false })
        }
        break;

      case that.data.LS_COMM_DEVICE_ID: //0x07,//设置设备ID 7
        if (buf[3] == 0) {
          console.log("ble", "设置设备信息成功")
        } else {
          console.log("ble", "设置设备信息失败")
        }

        break;
      case that.data.LS_COMM_OFFLINE: //0x0b,//设置离线密码编号+开关 b
        if (buf[3] == 0) {
          console.log("ble", "设置离线密码成功")
        } else {
          console.log("ble", "设置离线密码失败")
        }
        break;

      case that.data.LS_COMM_BATT_VALUE: //0x0d, //d

        if (headLen == 3) {
          var mBattValue = buf[3];
          console.log("ble", '获取电量成功：' + mBattValue)
          that.batteryCallback && that.batteryCallback({ success: true, data: mBattValue })
        } else {
          console.log("ble", '获取电量失败')
          that.batteryCallback && that.batteryCallback({ success: false })
        }
        break;

      case that.data.LS_COMM_CLEAR: // 0x10,//清空 10
        if (buf[3] == 0) {
          console.log("ble", '清空成功')
          that.clearUserCallback && that.clearUserCallback({
            success: true
          })
        } else {
          console.log("ble", '清空失败')
          that.clearUserCallback && that.clearUserCallback({
            success: false
          })

        }
        break;

      case that.data.LS_COMM_PWD_VALID: //0x11,//密码操作 增加 删除 修改--生效有效期 11
        if (buf[3] == 0) {
          console.log("ble", '设置用户  成功')
          var logs = [];
          this.memcpy(logs, buf, 3, 2);
          console.log("ble", '返回用户编号' + this.byteToString(logs))

          that.setUserCallback && that.setUserCallback({
            success: true,
            data: this.byteToString(logs)
          })
        } else {
          console.log("ble", '设置用户 ID失败')
          that.setUserCallback && that.setUserCallback({
            success: false
          })
        }
        break;

      case that.data.LS_COMM_OPENLOG_BIGDATA: //0x13,//开门记录 13
        if (headLen == 18) {
          var logs = [];

          this.memcpy(logs, buf, 3, 16);
          console.log("ble", '开门记录成功' + this.byteToString(logs))

          that.openLogCallback({
            success: true,
            data: this.byteToString(logs)
          })
        } else {
          console.log("ble", '开门记录失败')
          that.openLogCallback({
            success: false
          })
        }
        break;

      case that.data.LS_COMM_MAX_GET_MCUID: // 0x14,//获设备MCU ID
        if (headLen == 14) {
          console.log("ble", '获设备MCU ID 成功')
          var logs = [];

          this.memcpy(logs, buf, 3, 12);
          var mcuId = this.byteToString(logs)
          console.log("ble", 'MCU ID' + mcuId)
          this.getMcuCallback({
            success: true,
            data: mcuId
          })
        } else {
          console.log("ble", '获设备MCU ID失')
          this.getMcuCallback({
            success: false,
            data: "获取设备MCU ID失败"
          })
        }
        break;

      case that.data.LS_COMM_PROJECT: // 0x14,//获取工程版本
        if (headLen == 18) {
          console.log("ble", '获取工程版本  成功')
          var logs = [];

          this.memcpy(logs, buf, 3, 16);
          console.log("ble", '获取工程版本' + this.byteToString(logs))
        } else {
          console.log("ble", '获取工程版本 ID失败')
        }
        break;
      case that.data.LS_COMM_USER_VALID: // 0x12,//设置用户
        if (buf[3] == 0) {
          console.log("ble", '设置用户  成功')
          var logs = [];
          this.memcpy(logs, buf, 4, 2);
          console.log("ble", '返回用户编号' + this.byteToString(logs))
          that.setUserCallback && that.setUserCallback({
            success: true,
            data: this.byteToString(logs)
          })
        } else {
          console.log("ble", '设置用户 ID失败')
          that.setUserCallback && that.setUserCallback({
            success: false
          })
        }
        break;
      default:

        break;
    }

  }

  //字符串转buffer 十六进制
  stringToHexBuffer = function (data) {
    // var data = 'AA5504B10000B5'
    if (data) {
      var typedArray = new Uint8Array(data.match(/[\da-f]{2}/gi).map(function (h) {
        return parseInt(h, 16)
      }))

      return typedArray.buffer
    } else {
      return 0x0
    }
  }

  //数组转buffer 十六进制
  arraybuffToHexBuffer = function (data) {
    // var data = 'AA5504B10000B5'
    var typedArray = new Uint8Array(data.match(/[\da-f]{2}/gi).map(function (h) {
      return parseInt(h, 16)
    }))

    return typedArray
  }
  //let arrayBuffer = new Uint8Array(buf)
  // let str = this.buf2hex(arrayBuffer.buffer);
  //数组转字符串
  byteToString = function (buf) { // buffer is an ArrayBuffer
    let buffer = new Uint8Array(buf)
    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
  }

  StringToByte = function (str) { // buffer is an ArrayBuffer
    var array2 = this.stringToHexBuffer(str);
    return new Uint8Array(array2);
  }

  intToByte = function (value, len) { // buffer is an ArrayBuffer
    var i;
    var n = value;
    var list = [];
    for (i = 0; i < len; i++) {
      list[len - i - 1] = n % 0x100;
      n = n / 0x100;
    }

    return list;
  }

  memcpy = function (newbuf, oldbuf, startId, len) {
    var i;
    for (i = 0; i < len; i++) {
      newbuf[i] = oldbuf[startId + i];
    }
  }
  memcpy2 = function (newbuf, oldbuf, startId, startId2, len) {
    var i;
    for (i = 0; i < len; i++) {
      newbuf[startId + i] = oldbuf[startId2 + i];
    }
  }

  //获取服务
  getServiceAndCharacteristics(deviceId) {
    var that = this
    console.log(deviceId + "获取的deviceId")
    //不需要要扫描，就是知道service的uuid
    wx.getBLEDeviceServices({
      deviceId: deviceId,
      success: function (res) {
        console.log('服务', res)
        console.log(that.getServiceId() + "服务 uuid")
        that.linkto(that.getServiceId());
      },
      fail: function (res) {
        this.initFailCallback("服务扫描失败")
        console.log('服务扫描失败', res)
      }
    })
    // that.linkto(that.getServiceId());
  }

  /**
   * 连接上，获取session,心跳
   * uuid 服务serviceId
   */
  linkto(uuid) {
    var that = this
    //var uuid = e.currentTarget.id;
    console.log("linkto:" + uuid)
    console.log("linkto:" + this.deviceId)
    var deviceId = this.deviceId

    wx.getBLEDeviceCharacteristics({
      deviceId: deviceId,

      //  serviceId: that.getServiceId(),
      serviceId: uuid,
      success: res => {

        console.log('特征', res.characteristics)

        //console.log('监听通知'+ characteristic.characteristicId)
        //监听通知
        that.onBLECharacteristicValueChangeListener = characteristic => {
          if (characteristic.characteristicId.indexOf("FFF6") != -1) {
            const result = characteristic.value;
            const hex = that.buf2hex(result);
            that.blueRecieve(hex);
          }
        }
        wx.onBLECharacteristicValueChange(that.onBLECharacteristicValueChangeListener)
        console.log("userCharacteristcID：" + that.userCharacteristcID)
        wx.notifyBLECharacteristicValueChanged({

          deviceId: deviceId,
          serviceId: that.getServiceId(),
          //serviceId: e.currentTarget.id,
          // characteristicId: that.getReceiveId(),
          characteristicId: !that.userCharacteristcID ? '0000FFF6-0000-1000-8000-00805F9B34FB' : that.userCharacteristcID,
          state: true,
          success: function (res) {
            // success
            console.log('ble notify', res)
            that.blueSendPin();
          },
          fail: function (res) {
            console.log('失败', res)
            that.initFailCallback("监听通知返回失败")
          }
        })

      },
      fail: res => {
        console.log("获取蓝牙特征失败", res)
        that.initFailCallback("获取蓝牙特征失败")
      }
    })
  }

  //服务id
  getServiceId() {
    var platform = app.getPlatform()
    //ios 平台 服务id 中字母必须为大写
    if (platform == "ios") {
      console.log(this.serviceId.toUpperCase())
      return this.serviceId.toUpperCase();
    }
    //android 平台 服务id 中字母必须为小写
    else if (platform == "android") {
      return this.serviceId.toLowerCase();
    } else {
      return this.serviceId
    }
  }

  //arraybuffer 转字符串
  buf2char(buf) {
    var out = "";
    var u16a = new Uint16Array(buf);
    var single;
    for (var i = 0; i < u16a.length; i++) {
      single = u16a[i].toString(16)
      while (single.length < 4) single = "0".concat(single);
      out += "\\u" + single;
    }
    return out //eval("'"+out+ "'");
  }

  //获取发送id
  getSendId() {
    var platform = app.getPlatform()

    //ios 平台 服务id 中字母必须为大写
    if (platform == "ios") {
      return this.sendId.toUpperCase();
    }
    //android 平台 服务id 中字母必须为小写
    else if (platform == "android") {
      return this.sendId.toLowerCase();
    } else {
      return this.sendId
    }
  }

  buf2hex(buffer) { // buffer is an ArrayBuffer
    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
  }

  /**
   * 添加用户，密码 [0x23,0x45,0x67]
   * 只能三个字节
   * 有效期固定为2020-1-1~2099-12-31
   * 
   *    * 操作用户 增加删除及修改
   * 参数：操作类型 type,
   * 高4位:0表示添加，1表示删除，2表示修改有效期
   * 低4位:0表示指纹，1代表密码，2代表钥匙，3代表卡,
   * 添加卡时，长度为0，   密码默认为6位，也就是3字节
   * 0xb为密码管理员
   * @param {int} type 高4位:0表示添加，1表示删除，2表示修改有效期 低4位:0表示指纹，1代表密码，2代表钥匙，3代表卡,
   * @param {int} uid 密码编号 16进制 如:编号0001  应该是0x0001 parseInt("0001", 16)
   * @param {String} newPwd 密码 只能是0-9的数字，(比如123456后面会转为0x123456,但这里就会字符串好了)
   * @param {int} dataLen 密码长度 6位密码 dataLen为3
   */
  blueSendAddPwd(type, uid, newPwd, dataLen = 3) {
    var startTime; // 开始时间 startTime,
    var endTime; // 结束时间 endTime,
    // var dataLen = 3; //内容长度 dataLen,
    //startTime = 0x101020;
    //endTime = 0x201020;
    //2019-3-20 10:50
    // startTime = 19 * 0x40000 + 3 * 0x4000 + 20 * 0x200 + 10 * 0x10 + 10;
    startTime = 20 * 0x40000 + 1 * 0x4000 + 1 * 0x200 + 0 * 0x10 + 0;
    // endTime = 21 * 0x40000 + 3 * 0x4000 + 20 * 0x200 + 10 * 0x10 + 10;
    endTime = 99 * 0x40000 + 12 * 0x4000 + 31 * 0x200 + 0 * 0x10 + 0;

    /**
     * 时间转换格式
     * 21 * 0x40000 + 3 * 0x4000 + 20 * 0x200 + 10 * 0x10 + 10;;
     * 表示2021年3月20日10时50分（10*5）
     */
    // data = [0x12, 0x23, 0x34];

    this.blueSendChangeUser(type, startTime, endTime, uid, newPwd, dataLen);
  }

  /**
   * 可以用作修改密码
   * newPwd  0x234567  == 123456  密码减一
   * oldPwd 0x234567
   */
  blueSendOldAddUser(newPwd, oldPwd, uid) {
    var startTime; // 开始时间 startTime,
    var endTime; // 结束时间 endTime,
    var uid; //用户编号 uid,
    //pUart -> startTime=19 * 0x40000 + 3 * 0x4000 + 20 * 0x200 + 10 * 0x10 + 10;
    // newPwd = 0x223456; //密码最后值 为0x112345
    // newPwd = 0x223456;
    startTime = 0x000;
    endTime = 0x000;
    this.blueSendOldChangeUser(newPwd, oldPwd, startTime, endTime, uid);
  }

  /**
   * 设置时间
   * @param  date js date对象 
   * 如果 "" + year+month+day.....   strToByteArray 这样写位数会不对
   */
  blueSendDate(date) {
    var year = date.getFullYear()
    var month = date.getMonth() + 1
    var day = date.getDate()
    var hour = date.getHours()
    var minute = date.getMinutes()
    var second = date.getSeconds()
    var timeParam = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
    //年份低两位 20年
    var yearLastTwo = year % 100
    //年份高两位 20世纪
    var yearFirstTwo = year / 100
    timeParam[0] = 0x00 | parseInt("" + yearFirstTwo, 16)
    timeParam[1] = 0x00 | parseInt("" + yearLastTwo, 16)
    timeParam[2] = 0x00 | parseInt("" + month, 16)
    timeParam[3] = 0x00 | parseInt("" + day, 16)
    timeParam[4] = 0x00 | parseInt("" + hour, 16)
    timeParam[5] = 0x00 | parseInt("" + minute, 16)
    timeParam[6] = 0x00 | parseInt("" + second, 16)
    this.blueSendTime(timeParam)
  }

  /**
 * mac地址格式
 */
  array2mac(buffer) {
    let hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function (bit) {
        return ('00' + bit.toString(16)).slice(-2)
      }
    )
    return `${hexArr[7]}:${hexArr[6]}:${hexArr[5]}:${hexArr[2]}:${hexArr[1]}:${hexArr[0]}`
  }
}

export const bleLockHelper = new BleLockHelper()